﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Configuration.Install;
using System.Linq;
using System.Security.Principal;
using System.Security.AccessControl;
using System.IO;

namespace Genesis.Installer.Extensions
{
    [RunInstaller(true)]
    public partial class GenesisInstaller : System.Configuration.Install.Installer
    {
        protected System.Text.StringBuilder debugLog;
        protected Forms.Progress progress;
        protected string genesisApplicationPoolName;
        protected string installPath;

        public GenesisInstaller()
        {
            InitializeComponent();

            debugLog = new System.Text.StringBuilder();
            progress = new Genesis.Installer.Extensions.Forms.Progress();
            genesisApplicationPoolName = "GenesisApplicationPool";
            installPath = string.Empty;
        }

        protected void AddLogEntry(string DebugEntryFormatString, params object[] Parameters)
        {
            if (progress.Visible == false)
            {
                progress.Show();
            }

            progress.UpdateStatus(DebugEntryFormatString, Parameters);
            AddDebugEntry(DebugEntryFormatString, Parameters);
        }

        protected void AddDebugEntry(string DebugEntryFormatString, params object[] Parameters)
        {
            DateTime debugEntryDateTime = DateTime.Now;

            string debugEntry = string.Format("[{0} - {1}]\t\t{2}{3}",
                debugEntryDateTime.ToShortDateString(),
                debugEntryDateTime.ToShortTimeString(),
                string.Format(DebugEntryFormatString, Parameters),
                Environment.NewLine);

            debugLog.Append(debugEntry);

            if (installPath.Length > 0)
            {
                System.IO.StreamWriter logFile = System.IO.File.AppendText(installPath + "\\install.log");

                logFile.Write(debugEntry);

                logFile.Close();
            }
        }

        public override void Install(IDictionary stateSaver)
        {
            AddLogEntry("{0}", "Starting Genesis Smart Client Framework installation, please wait...");

            AddDebugEntry("{0}", "Executing Install base method");
            base.Install(stateSaver);
            AddDebugEntry("{0}", "Done");

            try
            {
                AddDebugEntry("{0}", "Getting install path");
                installPath = System.IO.Path.GetDirectoryName(
                    System.Reflection.Assembly.GetExecutingAssembly().Location);
                AddDebugEntry("{0} {1}", "Install path: ", installPath);

                installPath = System.IO.Directory.GetParent(installPath).FullName;
                AddDebugEntry("{0} {1}", "Install path parent: ", installPath);

                string sqlServer = string.Empty;
                string sqlUsername = string.Empty;
                string sqlPassword = string.Empty;
                string domain = string.Empty;
                string username = string.Empty;
                string password = string.Empty;
                bool createDatabase = false;
                bool registerIis = false;
                bool debug = false;
                bool userInputCancel = false;

                // Step 0
                // Get user settings
                if (progress.Visible)
                {
                    progress.Hide();
                }
                AddDebugEntry("{0}", "Creating User Input form");
                Forms.UserInput userInput = new Genesis.Installer.Extensions.Forms.UserInput();

                AddDebugEntry("{0}", "Creating Option control");
                Forms.Controls.Options optionsControl = new Genesis.Installer.Extensions.Forms.Controls.Options();
                userInput.LoadUserInputControl(optionsControl);

                AddDebugEntry("{0}", "Showing User Input form");
                System.Windows.Forms.DialogResult dialogResult = userInput.ShowDialog();

                if (dialogResult == System.Windows.Forms.DialogResult.OK)
                {
                    AddDebugEntry("{0}", "User Input Dialog Result is OK");

                    AddDebugEntry("{0}", "Creating SQL information control");
                    Forms.Controls.SQLServer sqlServerControl = new Genesis.Installer.Extensions.Forms.Controls.SQLServer();
                    userInput.LoadUserInputControl(sqlServerControl);

                    AddDebugEntry("{0}", "Showing User Input form");
                    dialogResult = userInput.ShowDialog();

                    if (dialogResult == System.Windows.Forms.DialogResult.OK)
                    {
                        AddDebugEntry("{0}", "User Input Dialog Result is OK");

                        AddDebugEntry("{0}", "Creating AD Security control");
                        Forms.Controls.ADSecurity adSecurityControl = new Genesis.Installer.Extensions.Forms.Controls.ADSecurity();
                        userInput.LoadUserInputControl(adSecurityControl);

                        AddDebugEntry("{0}", "Showing User Input form");
                        dialogResult = userInput.ShowDialog();

                        if (dialogResult == System.Windows.Forms.DialogResult.OK)
                        {
                            AddDebugEntry("{0}", "User Input Dialog Result is OK");

                            AddDebugEntry("{0}", "Creating base control");
                            Forms.Controls.Base baseControl = new Genesis.Installer.Extensions.Forms.Controls.Base();
                            userInput.LoadUserInputControl(baseControl);

                            if (userInput.Settings["SQLSERVER"] != null)
                            {
                                sqlServer = System.Convert.ToString(userInput.Settings["SQLSERVER"]);
                                AddDebugEntry("{0} ({1})", "SQLSERVER", sqlServer);
                            }
                            if (userInput.Settings["SQLUSERNAME"] != null)
                            {
                                sqlUsername = System.Convert.ToString(userInput.Settings["SQLUSERNAME"]);
                                AddDebugEntry("{0} ({1})", "SQLUSERNAME", sqlUsername);
                            }
                            if (userInput.Settings["SQLPASSWORD"] != null)
                            {
                                sqlPassword = System.Convert.ToString(userInput.Settings["SQLPASSWORD"]);
                                AddDebugEntry("{0} ({1})", "SQLPASSWORD", "********");
                            }
                            if (userInput.Settings["CREATEDATABASE"] != null)
                            {
                                createDatabase = System.Convert.ToBoolean(userInput.Settings["CREATEDATABASE"]);
                                AddDebugEntry("{0} ({1})", "CREATEDATABASE", createDatabase);
                            }
                            if (userInput.Settings["REGISTERIIS"] != null)
                            {
                                registerIis = System.Convert.ToBoolean(userInput.Settings["REGISTERIIS"]);
                                AddDebugEntry("{0} ({1})", "REGISTERIIS", registerIis);
                            }
                            if (userInput.Settings["DEBUG"] != null)
                            {
                                debug = System.Convert.ToBoolean(userInput.Settings["DEBUG"]);
                                AddDebugEntry("{0} ({1})", "DEBUG", debug);
                            }
                            if (userInput.Settings["DOMAIN"] != null)
                            {
                                domain = System.Convert.ToString(userInput.Settings["DOMAIN"]);
                                AddDebugEntry("{0} ({1})", "DOMAIN", domain);
                            }
                            if (userInput.Settings["USERNAME"] != null)
                            {
                                username = System.Convert.ToString(userInput.Settings["USERNAME"]);
                                AddDebugEntry("{0} ({1})", "USERNAME", username);
                            }
                            if (userInput.Settings["PASSWORD"] != null)
                            {
                                password = System.Convert.ToString(userInput.Settings["PASSWORD"]);
                                AddDebugEntry("{0} ({1})", "PASSWORD", "********");
                            }
                        }
                        else
                        {
                            userInputCancel = true;
                        }
                    }
                    else
                    {
                        userInputCancel = true;
                    }
                }
                else
                {
                    userInputCancel = true;
                }

                if (!userInputCancel)
                {
                    if (registerIis)
                    {
                        try
                        {
                            // Step 1
                            // Create Virtual Folders
                            AddLogEntry("{0}", "Creating Virtual Folders");
                            AddDebugEntry("{0}", "Creating Genesis.FileHost Virtual Folder");
                            iisVDirCreate("Default Web Site",
                                 "Genesis.FileHost",
                                 string.Format("{0}\\Web\\FileHost", installPath));
                            AddDebugEntry("{0}", "Creating Genesis.Management.Web Virtual Folder");
                            iisVDirCreate("Default Web Site",
                                 "Genesis.Management.Web",
                                 string.Format("{0}\\Web\\Management", installPath));
                            AddDebugEntry("{0}", "Creating Genesis.Web Virtual Folder");
                            iisVDirCreate("Default Web Site",
                                 "Genesis.Web",
                                 string.Format("{0}\\Web\\Genesis", installPath));
                            AddDebugEntry("{0}", "Creating Genesis.WebServices Virtual Folder");
                            iisVDirCreate("Default Web Site",
                                 "Genesis.WebServices",
                                 string.Format("{0}\\Web Services\\Genesis", installPath));
                        }
                        catch
                        {
                        }
                    }

                    // Step 1.1
                    // Modify web.config files
                    AddLogEntry("{0}", "Modifying app.config files");

                    // Genesis Genesis Host config
                    AddDebugEntry("{0}", "Modifying Genesis.Host.exe.config");
                    System.IO.StreamReader reader = System.IO.File.OpenText(string.Format("{0}\\Host\\Genesis.Host.exe.config", installPath));

                    string content = reader.ReadToEnd();

                    AddDebugEntry("{0}", "Closing reader");
                    reader.Close();

                    content = content.Replace("http://localhost:1480/Genesis.WebService/",
                        "http://localhost/Genesis.WebServices/");

                    AddDebugEntry("{0}", "Writing Genesis.Host.exe.config");
                    System.IO.FileStream writer = System.IO.File.Create(string.Format("{0}\\Host\\Genesis.Host.exe.config", installPath));

                    writer.Write(System.Text.UTF32Encoding.Default.GetBytes(content),
                        0,
                        System.Text.UTF32Encoding.Default.GetByteCount(content));

                    AddDebugEntry("{0}", "Closing Writer");
                    writer.Close();

                    AddLogEntry("{0}", "Modifying web.config files");

                    // Genesis FileHost web.config
                    AddDebugEntry("{0}", "Opening Genesis.FileHost web.config");
                    reader = System.IO.File.OpenText(string.Format("{0}\\Web\\FileHost\\web.config", installPath));

                    content = reader.ReadToEnd();

                    AddDebugEntry("{0}", "Closing reader");
                    reader.Close();

                    if (sqlServer != string.Empty)
                    {
                        content = content.Replace("Server=VSQL01\\SQL01;Initial Catalog=BlueMarble.Genesis.Dev;Integrated Security=SSPI;",
                            string.Format("Server={0};Database={1};Integrated Security={2};uid={3};pwd={4};",
                            sqlServer, "Genesis", "false", sqlUsername, sqlPassword));
                    }

                    content = content.Replace("http://localhost:1581/Genesis.FileHost/",
                        "http://localhost/Genesis.FileHost/");

                    AddDebugEntry("{0}", "Writing web.config");
                    writer = System.IO.File.Create(string.Format("{0}\\Web\\FileHost\\web.config", installPath));

                    writer.Write(System.Text.UTF32Encoding.Default.GetBytes(content),
                        0,
                        System.Text.UTF32Encoding.Default.GetByteCount(content));

                    AddDebugEntry("{0}", "Closing Writer");
                    writer.Close();

                    // Genesis Web Services web.config
                    AddDebugEntry("{0}", "Opening Genesis.WebServices web.config");
                    reader = System.IO.File.OpenText(string.Format("{0}\\Web Services\\Genesis\\web.config", installPath));

                    content = reader.ReadToEnd();

                    AddDebugEntry("{0}", "Closing reader");
                    reader.Close();

                    if (sqlServer != string.Empty)
                    {
                        content = content.Replace("Server=VSQL01\\SQL01;Initial Catalog=BlueMarble.Genesis.Dev;Integrated Security=SSPI;",
                            string.Format("Server={0};Database={1};Integrated Security={2};uid={3};pwd={4};",
                            sqlServer, "Genesis", "false", sqlUsername, sqlPassword));
                    }

                    content = content.Replace("http://localhost:1581/genesis.filehost/documents/",
                        "http://localhost/genesis.filehost/documents/");

                    content = content.Replace("C:\\Development\\VTFS01\\Genesis\\Code Project\\Web\\Genesis.FileHost\\Documents\\",
                        string.Format("{0}\\Web\\Genesis.FileHost\\Documents\\", installPath));

                    AddDebugEntry("{0}", "Writing web.config");
                    writer = System.IO.File.Create(string.Format("{0}\\Web Services\\Genesis\\web.config", installPath));

                    writer.Write(System.Text.UTF32Encoding.Default.GetBytes(content),
                        0,
                        System.Text.UTF32Encoding.Default.GetByteCount(content));

                    AddDebugEntry("{0}", "Closing Writer");
                    writer.Close();

                    // Genesis Web web.config
                    AddDebugEntry("{0}", "Opening Genesis.Web web.config");
                    reader = System.IO.File.OpenText(string.Format("{0}\\Web\\Genesis\\web.config", installPath));

                    content = reader.ReadToEnd();

                    AddDebugEntry("{0}", "Closing reader");
                    reader.Close();

                    if (sqlServer != string.Empty)
                    {
                        content = content.Replace("Server=VSQL01\\SQL01;Initial Catalog=BlueMarble.Genesis.Dev;Integrated Security=SSPI;",
                            string.Format("Server={0};Database={1};Integrated Security={2};uid={3};pwd={4};",
                            sqlServer, "Genesis", "false", sqlUsername, sqlPassword));
                    }

                    content = content.Replace("http://localhost:1581/Genesis.FileHost/",
                        "http://localhost/Genesis.FileHost/");

                    content = content.Replace("http://localhost:1581/genesis.filehost/documents/",
                        "http://localhost/genesis.filehost/documents/");

                    AddDebugEntry("{0}", "Writing web.config");
                    writer = System.IO.File.Create(string.Format("{0}\\Web\\Genesis\\web.config", installPath));

                    writer.Write(System.Text.UTF32Encoding.Default.GetBytes(content),
                        0,
                        System.Text.UTF32Encoding.Default.GetByteCount(content));

                    AddDebugEntry("{0}", "Closing Writer");
                    writer.Close();

                    // Genesis Management Web web.config
                    AddDebugEntry("{0}", "Opening Genesis.Management.Web web.config");
                    reader = System.IO.File.OpenText(string.Format("{0}\\Web\\Management\\web.config", installPath));

                    content = reader.ReadToEnd();
                    AddDebugEntry("{0}:\t{1}", "Content", content);

                    AddDebugEntry("{0}", "Closing reader");
                    reader.Close();

                    content = content.Replace("http://localhost:1480/Genesis.WebService/",
                        "http://localhost/Genesis.WebServices/");

                    AddDebugEntry("{0}", "Writing web.config");
                    writer = System.IO.File.Create(string.Format("{0}\\Web\\Management\\web.config", installPath));

                    writer.Write(System.Text.UTF32Encoding.Default.GetBytes(content),
                        0,
                        System.Text.UTF32Encoding.Default.GetByteCount(content));

                    AddDebugEntry("{0}", "Closing Writer");
                    writer.Close();

                    if (createDatabase)
                    {
                        if (sqlServer != string.Empty)
                        {
                            // Step 2
                            // Modify Database script
                            AddLogEntry("{0}", "Modifying database script");

                            // Database.sql
                            AddDebugEntry("{0}", "Opening assemblies.sql");
                            reader = System.IO.File.OpenText(string.Format("{0}\\Database\\assemblies.sql", installPath));

                            content = reader.ReadToEnd();
                            AddDebugEntry("{0}:\t{1}", "Content", content);

                            AddDebugEntry("{0}", "Closing reader");
                            reader.Close();

                            content = content.Replace("<%INSTALLPATH%>",
                                installPath);

                            AddDebugEntry("{0}", "Writing web.config");
                            writer = System.IO.File.Create(string.Format("{0}\\Database\\assemblies.sql", installPath));

                            writer.Write(System.Text.UTF32Encoding.Default.GetBytes(content),
                                0,
                                System.Text.UTF32Encoding.Default.GetByteCount(content));

                            AddDebugEntry("{0}", "Closing Writer");
                            writer.Close();

                            // Step 2.1
                            // Execute Database script
                            AddLogEntry("{0}", "Executing database script");

                            AddDebugEntry("{0}", "Opening SQL Database connection");
                            System.Data.SqlClient.SqlConnection connection = new System.Data.SqlClient.SqlConnection(
                                string.Format("Server={0};Database={1};Integrated Security={2};uid={3};pwd={4};",
                                sqlServer, "master", "false", sqlUsername, sqlPassword));

                            connection.Open();

                            try
                            {
                                // database.sql
                                this.executeNonQuery(string.Format("{0}\\Database\\database.sql", installPath),
                                    connection);
                            }
                            catch
                            {
                            }

                            connection.Close();

                            AddDebugEntry("{0}", "Opening SQL Database connection");
                            connection = new System.Data.SqlClient.SqlConnection(
                                string.Format("Server={0};Database={1};Integrated Security={2};uid={3};pwd={4};",
                                sqlServer, "Genesis", "false", sqlUsername, sqlPassword));

                            connection.Open();

                            try
                            {
                                // tables.sql
                                this.executeNonQuery(string.Format("{0}\\Database\\tables.sql", installPath),
                                    connection);
                            }
                            catch
                            {
                            }

                            try
                            {
                                // assemblies.sql
                                this.executeNonQuery(string.Format("{0}\\Database\\assemblies.sql", installPath),
                                    connection);
                            }
                            catch
                            {
                            }

                            try
                            {
                                // storedprocedures.sql
                                this.executeNonQuery(string.Format("{0}\\Database\\storedprocedures.sql", installPath),
                                    connection);
                            }
                            catch
                            {
                            }

                            try
                            {
                                // data.sql
                                this.executeNonQuery(string.Format("{0}\\Database\\data.sql", installPath),
                                    connection);
                            }
                            catch
                            {
                            }

                            connection.Close();
                        }
                    }

                    // Step 5
                    // Set folder access
                    string ADDomain = domain;
                    string ADUser = username;
                    AddDebugEntry("{0}:\t{1}\\{2}", "Security Account", domain, username);
                    string Path = string.Format("{0}\\Web\\", installPath);

                    // Remove any inheritable permissions from the path 
                    //RemoveInheritablePermissons(Path);

                    try
                    {
                        AddLogEntry("{0} {1} for {2}\\{3}", "Setting Security on", Path, domain, username);
                        // Add the access control entries for the path 
                        AddDirectorySecurity(Path, ADDomain + "\\" + ADUser, FileSystemRights.FullControl,
                                             InheritanceFlags.ContainerInherit | InheritanceFlags.ObjectInherit,
                                             PropagationFlags.InheritOnly, AccessControlType.Allow);
                    }
                    catch
                    {
                    }

                    try
                    {
                        AddDebugEntry("{0} {1} for {2}", "Setting Security on", Path, "System");
                        // Add the access control entries for the path 
                        AddDirectorySecurity(Path, "SYSTEM", FileSystemRights.FullControl,
                                             InheritanceFlags.ContainerInherit | InheritanceFlags.ObjectInherit,
                                             PropagationFlags.InheritOnly, AccessControlType.Allow);
                    }
                    catch
                    {
                    }

                    try
                    {
                        // Add the access control entries for the path 
                        AddDebugEntry("{0} {1} for {2}", "Setting Security on", Path, "Creator Owner");
                        AddDirectorySecurity(Path, "CREATOR OWNER", FileSystemRights.FullControl,
                                             InheritanceFlags.ContainerInherit | InheritanceFlags.ObjectInherit,
                                             PropagationFlags.InheritOnly, AccessControlType.Allow);
                    }
                    catch
                    {
                    }

                    try
                    {
                        // Add the access control entries for the path 
                        AddDebugEntry("{0} {1} for {2}", "Setting Security on", Path, "Creator Owner");
                        AddDirectorySecurity(Path, "IIS AppPool\\DefaultAppPool", FileSystemRights.FullControl,
                                             InheritanceFlags.ContainerInherit | InheritanceFlags.ObjectInherit,
                                             PropagationFlags.InheritOnly, AccessControlType.Allow);
                    }
                    catch
                    {
                    }

                    Path = string.Format("{0}\\Web Services\\", installPath);

                    // Remove any inheritable permissions from the path 
                    //RemoveInheritablePermissons(Path);

                    try
                    {
                        // Add the access control entries for the path 
                        AddLogEntry("{0} {1} for {2}\\{3}", "Setting Security on", Path, domain, username);
                        AddDirectorySecurity(Path, ADDomain + "\\" + ADUser, FileSystemRights.FullControl,
                                             InheritanceFlags.ContainerInherit | InheritanceFlags.ObjectInherit,
                                             PropagationFlags.InheritOnly, AccessControlType.Allow);
                    }
                    catch
                    {
                    }

                    try
                    {
                        // Add the access control entries for the path 
                        AddDebugEntry("{0} {1} for {2}", "Setting Security on", Path, "System");
                        AddDirectorySecurity(Path, "SYSTEM", FileSystemRights.FullControl,
                                             InheritanceFlags.ContainerInherit | InheritanceFlags.ObjectInherit,
                                             PropagationFlags.InheritOnly, AccessControlType.Allow);
                    }
                    catch
                    {
                    }

                    try
                    {
                        // Add the access control entries for the path 
                        AddDebugEntry("{0} {1} for {2}", "Setting Security on", Path, "Creator Owner");
                        AddDirectorySecurity(Path, "CREATOR OWNER", FileSystemRights.FullControl,
                                             InheritanceFlags.ContainerInherit | InheritanceFlags.ObjectInherit,
                                             PropagationFlags.InheritOnly, AccessControlType.Allow);
                    }
                    catch
                    {
                    }

                    Path = string.Format("{0}\\Host\\", installPath);

                    // Remove any inheritable permissions from the path 
                    //RemoveInheritablePermissons(Path);

                    try
                    {
                        // Add the access control entries for the path 
                        AddLogEntry("{0} {1} for {2}\\{3}", "Setting Security on", Path, domain, username);
                        AddDirectorySecurity(Path, ADDomain + "\\" + ADUser, FileSystemRights.FullControl,
                                             InheritanceFlags.ContainerInherit | InheritanceFlags.ObjectInherit,
                                             PropagationFlags.InheritOnly, AccessControlType.Allow);
                    }
                    catch
                    {
                    }

                    try
                    {
                        // Add the access control entries for the path 
                        AddDebugEntry("{0} {1} for {2}", "Setting Security on", Path, "System");
                        AddDirectorySecurity(Path, "SYSTEM", FileSystemRights.FullControl,
                                             InheritanceFlags.ContainerInherit | InheritanceFlags.ObjectInherit,
                                             PropagationFlags.InheritOnly, AccessControlType.Allow);
                    }
                    catch
                    {
                    }

                    try
                    {
                        // Add the access control entries for the path 
                        AddDebugEntry("{0} {1} for {2}", "Setting Security on", Path, "Creator Owner");
                        AddDirectorySecurity(Path, "CREATOR OWNER", FileSystemRights.FullControl,
                                             InheritanceFlags.ContainerInherit | InheritanceFlags.ObjectInherit,
                                             PropagationFlags.InheritOnly, AccessControlType.Allow);
                    }
                    catch
                    {
                    }


                    //// Step 6
                    //// Register components in Visual Studio
                    //AddLogEntry("{0}", "Registering application in Visual Studio");
                    //AddDebugEntry("Opening {0}", "HKEY_LOCAL_MACHINE");
                    //Microsoft.Win32.RegistryKey localMachineKey = Microsoft.Win32.Registry.LocalMachine;
                    //AddDebugEntry("Opening {0}", "SOFTWARE");
                    //Microsoft.Win32.RegistryKey softwareKey = localMachineKey.OpenSubKey("SOFTWARE");
                    //AddDebugEntry("Opening {0}", "Microsoft");
                    //Microsoft.Win32.RegistryKey microsoftKey = softwareKey.OpenSubKey("Microsoft");
                    //AddDebugEntry("Opening {0}", ".NETFramework");
                    //Microsoft.Win32.RegistryKey dotNetFrameworkKey = microsoftKey.OpenSubKey(".NETFramework");
                    //AddDebugEntry("Opening {0}", "AssemblyFolders");
                    //Microsoft.Win32.RegistryKey assemblyFoldersKey = dotNetFrameworkKey.OpenSubKey("AssemblyFolders");

                    //AddDebugEntry("{0}", "Scanning Assembly Folders...");
                    //string[] assemblySubKeys = assemblyFoldersKey.GetSubKeyNames();

                    //if (assemblySubKeys == null)
                    //{
                    //    assemblySubKeys = new string[] { };
                    //}

                    //Microsoft.Win32.RegistryKey subKey = null;
                    //bool foundClient = false;
                    //bool foundCommon = false;

                    //foreach (string assemblySubKey in assemblySubKeys)
                    //{
                    //    AddDebugEntry("{0}: {1}", "Found Assembly Folder", assemblySubKey);

                    //    if (assemblySubKey == "BlueMarble.Genesis.Client")
                    //    {
                    //        AddDebugEntry("{0}", "Updating Client Assembly Folders");

                    //        subKey = assemblyFoldersKey.OpenSubKey("BlueMarble.Genesis.Client", true);

                    //        subKey.SetValue(string.Empty, "C:\\Program Files\\Blue Marble\\Genesis Smart Client Framework\\Assemblies\\Client");

                    //        subKey.Close();

                    //        foundClient = true;
                    //    }

                    //    if (assemblySubKey == "BlueMarble.Genesis.Common")
                    //    {
                    //        AddDebugEntry("{0}", "Updating Common Assembly Folders");

                    //        subKey = assemblyFoldersKey.OpenSubKey("BlueMarble.Genesis.Common", true);

                    //        subKey.SetValue(string.Empty, "C:\\Program Files\\Blue Marble\\Genesis Smart Client Framework\\Assemblies\\Common");

                    //        subKey.Close();

                    //        foundCommon = true;
                    //    }
                    //}

                    //if (!foundClient)
                    //{
                    //    AddDebugEntry("{0}", "Adding Client Assembly Folders");

                    //    subKey = assemblyFoldersKey.OpenSubKey("BlueMarble.Genesis.Client", true);

                    //    subKey.SetValue(string.Empty, "C:\\Program Files\\Blue Marble\\Genesis Smart Client Framework\\Assemblies\\Client");

                    //    subKey.Close();
                    //}

                    //if (!foundCommon)
                    //{
                    //    AddDebugEntry("{0}", "Adding Common Assembly Folders");

                    //    subKey = assemblyFoldersKey.OpenSubKey("BlueMarble.Genesis.Common", true);

                    //    subKey.SetValue(string.Empty, "C:\\Program Files\\Blue Marble\\Genesis Smart Client Framework\\Assemblies\\Common");

                    //    subKey.Close();
                    //}

                    //assemblyFoldersKey.Close();
                }
                else
                {
                    throw new Exception("User Input error");
                }

                if (progress.Visible)
                {
                    progress.Hide();
                }

                if (debug)
                {
                    Forms.Debug debugForm = new Genesis.Installer.Extensions.Forms.Debug();

                    debugForm.richTextBox.Text = debugLog.ToString();

                    debugForm.ShowDialog();
                }
            }
            catch (System.Exception exception)
            {
                if (progress.Visible)
                {
                    progress.Hide();
                }

                AddDebugEntry("{0}:\t\t{1}", "Message", exception.Message);
                AddDebugEntry("{0}:\t\t{1}", "Source", exception.Source);
                AddDebugEntry("{0}:\t\t{1}", "Stack Trace", exception.StackTrace);

                if (exception.InnerException != null)
                {
                    processInnerException(exception.InnerException);
                }

                Forms.Debug debug = new Genesis.Installer.Extensions.Forms.Debug();

                debug.richTextBox.Text = debugLog.ToString();

                debug.ShowDialog();

                throw;
            }
        }

        protected void executeNonQuery(string filePath, System.Data.SqlClient.SqlConnection connection)
        {
            AddDebugEntry("{0} {1}", "Opening", new System.IO.FileInfo(filePath).Name);
            System.IO.StreamReader reader = System.IO.File.OpenText(filePath);

            AddDebugEntry("{0}", "Creating String Builder");
            System.Text.StringBuilder commandText = new System.Text.StringBuilder();

            while (reader.Peek() != -1)
            {
                string line = reader.ReadLine();

                if (line != "GO")
                {
                    commandText.AppendLine(line);
                }

                if (line == "GO")
                {
                    AddDebugEntry("{0}:\t\t{1}", "CommandText", commandText.ToString());

                    AddDebugEntry("{0}", "Creating SQL Database command");
                    System.Data.SqlClient.SqlCommand command =
                        new System.Data.SqlClient.SqlCommand(commandText.ToString(), connection);

                    AddLogEntry("{0}{1}{2}:\t{3}", "Executing SQL Database command",
                        Environment.NewLine,
                        "from",
                        new System.IO.FileInfo(filePath).Name);
                    command.ExecuteNonQuery();

                    AddDebugEntry("{0}", "Creating String Builder");
                    commandText = new System.Text.StringBuilder();
                }
            }

            AddDebugEntry("{0}", "Closing reader");
            reader.Close();
        }

        protected void processInnerException(System.Exception InnerException)
        {
            AddDebugEntry("{0}",
                "================================================================================");

            AddDebugEntry("{0}:\t\t{1}", "Message", InnerException.Message);
            AddDebugEntry("{0}:\t\t{1}", "Source", InnerException.Source);
            AddDebugEntry("{0}:\t\t{1}", "Stack Trace", InnerException.StackTrace);

            if (InnerException.InnerException != null)
            {
                processInnerException(InnerException.InnerException);
            }
        }

        protected void iisVDirCreate(string WebSiteName, string VirtualDirectoryName, string PhysicalPath)
        {
            AddLogEntry("{0}", "Configuring Internet Information Services");

            AddDebugEntry("{0} ({1}, {2}, {3})", "iisVDirCreate executed",
                WebSiteName, VirtualDirectoryName, PhysicalPath);

            AddDebugEntry("{0}", "Connecting to the IIS Service");
            IIsManager.IIsService service = new IIsManager.IIsService();
            AddDebugEntry("{0}", "Connected");

            IIsManager.IIsApplicationPool applicationPool = null;
            IIsManager.IIsSite site = null;
            IIsManager.IIsVirtualDirectory virtualDirectory = null;

            AddDebugEntry("{0} ({1})", "Searching for Web Site", WebSiteName);
            foreach (IIsManager.IIsSite _site in service.Sites)
            {
                if (_site.Description == WebSiteName)
                {
                    site = _site;

                    AddDebugEntry("{0} ({1})", "Found Web Site", WebSiteName);
                    break;
                }
            }

            if (site != null)
            {
                AddDebugEntry("{0}", "Searching for Genesis Application Pool");
                foreach (IIsManager.IIsApplicationPool _applicationPool in service.ApplicationPools)
                {
                    if (_applicationPool.Id == genesisApplicationPoolName)
                    {
                        applicationPool = _applicationPool;

                        AddDebugEntry("{0}", "Found Genesis Application Pool");
                        break;
                    }
                }

                if (applicationPool == null)
                {
                    AddDebugEntry("{0}", "Genesis Application Pool NOT found!");
                    AddDebugEntry("{0}", "Creating Genesis Application Pool");
                    applicationPool = service.AddAppPool(genesisApplicationPoolName);
                }

                AddDebugEntry("{0} ({1})", "Searching for Virtual Directory", VirtualDirectoryName);
                foreach (IIsManager.IIsVirtualDirectory _virtualDirectory in site.VirtualDirectories)
                {
                    if (_virtualDirectory.Name == VirtualDirectoryName)
                    {
                        virtualDirectory = _virtualDirectory;

                        AddDebugEntry("{0} ({1})", "Found Virtual Directory", VirtualDirectoryName);
                        break;
                    }
                }

                if (virtualDirectory == null)
                {
                    AddDebugEntry("{0}", "Virtual Directory NOT found!");
                    AddDebugEntry("{0} ({1})", "Creating Virtual Directory", VirtualDirectoryName);
                    virtualDirectory = site.AddVirtualDirectory(
                        VirtualDirectoryName, PhysicalPath);
                }

                AddDebugEntry("{0}", "Setting Virtual Directory Access Permissions");
                virtualDirectory.AccessPermissions = IIsManager.AccessPermissionFlags.Read |
                    IIsManager.AccessPermissionFlags.Script |
                    IIsManager.AccessPermissionFlags.Execute |
                    IIsManager.AccessPermissionFlags.Write;

                //AddDebugEntry("{0}", "Creating Virtual Directory Application");
                //virtualDirectory.CreateApplication(VirtualDirectoryName.Replace(".", ""),
                //    "");
                //AddDebugEntry("{0}", "Set Virtual Directory ASP.NET Version");
                //virtualDirectory.ASPNETVersion = IIsManager.ASPNETVersions.v2_0_50727;

                AddDebugEntry("{0}", "Set Virtual Directory Authentication Methods");
                virtualDirectory.AuthenticationMethods = IIsManager.AuthenticationFlags.Integrated;
            }
        }

        public override void Uninstall(IDictionary savedState)
        {
            AddDebugEntry("{0}", "Executing Install base method");
            base.Uninstall(savedState);
            AddDebugEntry("{0}", "Done");

            try
            {
                AddLogEntry("{0}", "Uninstalling from your computer, please wait...");

                if (progress.Visible)
                {
                    progress.Hide();
                }
            }
            catch (System.Exception exception)
            {
                if (progress.Visible)
                {
                    progress.Hide();
                }

                AddDebugEntry("{0}:\t\t{1}", "Message", exception.Message);
                AddDebugEntry("{0}:\t\t{1}", "Source", exception.Source);
                AddDebugEntry("{0}:\t\t{1}", "Stack Trace", exception.StackTrace);

                if (exception.InnerException != null)
                {
                    processInnerException(exception.InnerException);
                }

                Forms.Debug debug = new Genesis.Installer.Extensions.Forms.Debug();

                debug.richTextBox.Text = debugLog.ToString();

                debug.ShowDialog();

                throw;
            }
        }

        protected void iisVDirDelete(string WebSiteName, string VirtualDirectoryName)
        {
            AddDebugEntry("{0} ({1}, {2})", "iisVDirDelete executed",
                WebSiteName, VirtualDirectoryName);

            AddDebugEntry("{0}", "Connecting to the IIS Service");
            IIsManager.IIsService service = new IIsManager.IIsService();
            AddDebugEntry("{0}", "Connected");

            IIsManager.IIsSite site = null;

            AddDebugEntry("{0} ({1})", "Searching for Web Site", WebSiteName);
            foreach (IIsManager.IIsSite _site in service.Sites)
            {
                if (_site.Description == WebSiteName)
                {
                    site = _site;

                    AddDebugEntry("{0} ({1})", "Found Web Site", WebSiteName);
                    break;
                }
            }
        }// Adds an ACL entry on the specified directory for the specified account. 
        public static void AddDirectorySecurity(string FileName, string Account, FileSystemRights Rights,
                                                InheritanceFlags Inheritance, PropagationFlags Propogation,
                                                AccessControlType ControlType)
        {
            // Create a new DirectoryInfo object. 
            DirectoryInfo dInfo = new DirectoryInfo(FileName);
            // Get a DirectorySecurity object that represents the  
            // current security settings. 
            DirectorySecurity dSecurity = dInfo.GetAccessControl();
            // Add the FileSystemAccessRule to the security settings.  
            dSecurity.AddAccessRule(new FileSystemAccessRule(Account,
                                                             Rights,
                                                             Inheritance,
                                                             Propogation,
                                                             ControlType));
            // Set the new access settings. 
            dInfo.SetAccessControl(dSecurity);
        }

        // Removes an ACL entry on the specified directory for the specified account. 
        public static void RemoveDirectorySecurity(string FileName, string Account, FileSystemRights Rights,
                                                   AccessControlType ControlType)
        {
            // Create a new DirectoryInfo object. 
            DirectoryInfo dInfo = new DirectoryInfo(FileName);
            // Get a DirectorySecurity object that represents the  
            // current security settings. 
            DirectorySecurity dSecurity = dInfo.GetAccessControl();
            // Add the FileSystemAccessRule to the security settings.  
            dSecurity.RemoveAccessRule(new FileSystemAccessRule(Account,
                                                                Rights,
                                                                ControlType));
            // Set the new access settings. 
            dInfo.SetAccessControl(dSecurity);
        }

        // Removes an ACL entry on the specified directory for the specified account. 
        public static void RemoveInheritablePermissons(string FileName)
        {
            // Create a new DirectoryInfo object. 
            DirectoryInfo dInfo = new DirectoryInfo(FileName);
            // Get a DirectorySecurity object that represents the  
            // current security settings. 
            DirectorySecurity dSecurity = dInfo.GetAccessControl();
            // Add the FileSystemAccessRule to the security settings. 
            const bool IsProtected = true;
            const bool PreserveInheritance = false;
            dSecurity.SetAccessRuleProtection(IsProtected, PreserveInheritance);
            // Set the new access settings. 
            dInfo.SetAccessControl(dSecurity);
        }

        public override void Commit(IDictionary savedState)
        {
            AddDebugEntry("{0}", "Executing Install base method");
            base.Commit(savedState);
            AddDebugEntry("{0}", "Done");

            try
            {
                AddLogEntry("{0}", "Committing installation to your computer, please wait...");

                // Step 0
                // Confirm installation
                if (progress.Visible)
                {
                    progress.Hide();
                }
                AddDebugEntry("{0}", "Creating User Input form");
                Forms.UserInput userInput = new Genesis.Installer.Extensions.Forms.UserInput();

                AddDebugEntry("{0}", "Creating Commit control");
                Forms.Controls.Commit commitControl = new Genesis.Installer.Extensions.Forms.Controls.Commit();
                userInput.LoadUserInputControl(commitControl);

                AddDebugEntry("{0}", "Showing User Input form");
                System.Windows.Forms.DialogResult dialogResult = userInput.ShowDialog();

                if (dialogResult == System.Windows.Forms.DialogResult.OK)
                {
                }

                if (progress.Visible)
                {
                    progress.Hide();
                }
            }
            catch (System.Exception exception)
            {
                if (progress.Visible)
                {
                    progress.Hide();
                }

                AddDebugEntry("{0}:\t\t{1}", "Message", exception.Message);
                AddDebugEntry("{0}:\t\t{1}", "Source", exception.Source);
                AddDebugEntry("{0}:\t\t{1}", "Stack Trace", exception.StackTrace);

                if (exception.InnerException != null)
                {
                    processInnerException(exception.InnerException);
                }

                Forms.Debug debug = new Genesis.Installer.Extensions.Forms.Debug();

                debug.richTextBox.Text = debugLog.ToString();

                debug.ShowDialog();

                throw;
            }
        }

        public override void Rollback(IDictionary savedState)
        {
            AddDebugEntry("{0}", "Executing Install base method");
            base.Rollback(savedState);
            AddDebugEntry("{0}", "Done");

            try
            {
                AddLogEntry("{0}", "Rolling back installation from your computer, please wait...");
                
                // Step 0
                // Rollback confirmation
                if (progress.Visible)
                {
                    progress.Hide();
                }
                AddDebugEntry("{0}", "Creating User Input form");
                Forms.UserInput userInput = new Genesis.Installer.Extensions.Forms.UserInput();

                AddDebugEntry("{0}", "Creating Commit control");
                Forms.Controls.Rollback rollbackControl = new Genesis.Installer.Extensions.Forms.Controls.Rollback();
                userInput.LoadUserInputControl(rollbackControl);

                AddDebugEntry("{0}", "Showing User Input form");
                System.Windows.Forms.DialogResult dialogResult = userInput.ShowDialog();

                if (dialogResult == System.Windows.Forms.DialogResult.OK)
                {
                }

                if (progress.Visible)
                {
                    progress.Hide();
                }
            }
            catch (System.Exception exception)
            {
                if (progress.Visible)
                {
                    progress.Hide();
                }

                AddDebugEntry("{0}:\t\t{1}", "Message", exception.Message);
                AddDebugEntry("{0}:\t\t{1}", "Source", exception.Source);
                AddDebugEntry("{0}:\t\t{1}", "Stack Trace", exception.StackTrace);

                if (exception.InnerException != null)
                {
                    processInnerException(exception.InnerException);
                }

                Forms.Debug debug = new Genesis.Installer.Extensions.Forms.Debug();

                debug.richTextBox.Text = debugLog.ToString();

                debug.ShowDialog();

                throw;
            }
        }
    }
}
